package com.sixeco.apigetway.handle;

import java.net.SocketAddress;
import java.util.function.BiConsumer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sixeco.apigetway.common.CommonIO;
import com.sixeco.apigetway.common.CommonVar;

import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.ScheduledFuture;

public class BcHttpHandle extends ChannelInboundHandlerAdapter {


	
	
	Logger logger = LoggerFactory.getLogger(getClass());
	
	Logger loggerStat = LoggerFactory.getLogger("getWayStatL");
	
	
	final BiConsumer<Channel, SocketAddress> reconnectConsumer;
	
	public BcHttpHandle(BiConsumer<Channel, SocketAddress> reconnectConsumer) {
		this.reconnectConsumer=reconnectConsumer;
	}


	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		super.channelActive(ctx);

	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		super.channelInactive(ctx);

		Channel channel=ctx.channel();
		
		SocketAddress socketAddress=channel.remoteAddress();
		
		
		/**
		 * 连接断开的时候不能取消任务，否则会取消前置channel的重写，这个过程会导致前置channel一直等待响应http
		 */
		//	cancelTask(channel);
		if (logger.isDebugEnabled()) {
			logger.debug("remote channel is close{},it will reconnect",socketAddress);
		}
		
		if(reconnectConsumer!=null) {
			
			reconnectConsumer.accept(channel,channel.remoteAddress());
		}
	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

		if (msg instanceof FullHttpResponse) {
			
			Channel channel=ctx.channel();
	
			writeAbChannel(channel, (FullHttpResponse) msg);
			
			stat(channel);

		} else {
			ctx.close();
		}
	}
	
	/**
	 * 写入到前置channel
	 * @param abChannel
	 * @param fullHttpResponse
	 */
	private  void  writeAbChannel(Channel channel,FullHttpResponse fullHttpResponse) {
		
		
		
		AttributeKey<Channel> abChannelAttr=CommonVar.Proxy.abChannelAttr;
		if(!channel.hasAttr(abChannelAttr)) {
			logger.warn("写时前置的channel不存在了?");
			return;
		}

		Channel abChannel=channel.attr(abChannelAttr).get();
	
		fullHttpResponse.headers().set("Server", "sixeco-getway");
		
		
		if(!abChannel.isActive()) {
			logger.warn("前置的channel关闭了?");
			return;
		}
		
		abChannel.writeAndFlush(fullHttpResponse).addListener((l)->{
			
			if(!l.isSuccess()) {
				
				
				logger.warn("写入abchannel失败",l.cause());
				logger.info("content{}",fullHttpResponse);
				
				
				FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
						HttpResponseStatus.BAD_GATEWAY, Unpooled.wrappedBuffer(CommonVar.HttpChunk.proxyErrr));
				
				
				abChannel.writeAndFlush(response);
				
				
			}else {
				cancelTask(channel);
			}
			
			
		});
		
		
	}

	private void stat(Channel bcChannel) {
		
		
		AttributeKey<Channel> abChannelAttr=CommonVar.Proxy.abChannelAttr;
		if(!bcChannel.hasAttr(abChannelAttr)) {
			logger.warn("stat时前置的channel不存在了?");
			return;
		}

		Channel abChannel=bcChannel.attr(abChannelAttr).get();
		
		
		if(abChannel==null) {
			logger.warn("统计阶段channel为空");
			return;
		}
		
		 AttributeKey<Long> lastRequestTime=CommonVar.Proxy.lastRequestTime;
		 
		 if(abChannel.hasAttr(lastRequestTime)) {
			 long lastTime=abChannel.attr(CommonVar.Proxy.lastRequestTime).get();
				long nowTime=System.currentTimeMillis();
				
				
				 String uri=abChannel.attr(CommonVar.Proxy.lastRequestUri).get();
				 int times=abChannel.attr(CommonVar.Proxy.requstCount).get().get();
				
				 loggerStat.info("路径{}->{}请求耗时{},请求次数{}",uri,abChannel.remoteAddress(),nowTime-lastTime,times);
		 }
		
		
	}

	

	@Override
	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
		super.channelReadComplete(ctx);
		ctx.flush();
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

		

		Channel abChannel=null;
		Channel channel=ctx.channel();
		
		
		AttributeKey<Channel> abChannelAttr=CommonVar.Proxy.abChannelAttr;
		if(!channel.hasAttr(abChannelAttr)) {
			logger.warn("exception前置的channel不存在了?");
			return;
		}
		
		
		abChannel=channel.attr(abChannelAttr).get();
		
		if(!abChannel.isActive()) {
			logger.warn("前置的channel关闭了?");
			return;
		}
		
		
		AttributeKey<ScheduledFuture<?>> reWriteFuture=CommonVar.Proxy.reWriteFuture;
		
		
		/**
		 * 如果有定时任务就等定时任务来处理，如果没有定时任务了就直接返回给前置channel
		 */
		if(!channel.hasAttr(reWriteFuture)||
				channel.attr(reWriteFuture).get()==null) {
						
			FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
					HttpResponseStatus.BAD_GATEWAY, Unpooled.wrappedBuffer(CommonVar.HttpChunk.proxyErrr));
			CommonIO.getInstance().writeMsgAndClose(abChannel, response);
			
		}
		
		stat(channel);
		logger.warn("代理异常",cause);
		
	}
	
	/**
	 * 取消bcchannel里面的重发任务
	 * @param channel
	 */
	public static void cancelTask(Channel channel) {
		
		/**
		 * 删除以前的定时任务
		 */
		ScheduledFuture<?> scheduledFuture=null;
		AttributeKey<ScheduledFuture<?>> reWriteFuture=CommonVar.Proxy.reWriteFuture;
		
		if(channel.hasAttr(reWriteFuture)) {
			scheduledFuture=channel.attr(reWriteFuture).get();
			if(scheduledFuture!=null) {
				scheduledFuture.cancel(false);
			}
		}
	}
}
